package com.qingcloud.df.executor.controller;

import com.qingcloud.base.exception.WamingException;
import com.qingcloud.df.executor.cluster.ClusterManager;
import com.qingcloud.df.executor.cluster.JobService;
import com.qingcloud.df.executor.constant.RuntimeConfigKeyConstant;
import com.qingcloud.df.executor.enums.OpResultEnum;
import com.qingcloud.df.executor.service.TaskService;
import com.qingcloud.df.sdk.component.config.ComponentConfig;
import com.qingcloud.df.sdk.component.config.SystemRuntimeInfo;
import com.qingcloud.df.sdk.component.context.CompInstContext;
import com.qingcloud.df.sdk.component.context.ConfigManager;
import com.qingcloud.df.sdk.component.context.ConfigService;
import com.qingcloud.df.sdk.component.message.request.*;
import com.qingcloud.df.sdk.component.message.response.ExecutorStatus;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import com.qingcloud.base.remote.executor.ExecutorParam;
import com.qingcloud.base.pojo.ApiResult;

import javax.annotation.Resource;
import java.util.List;

/**
 * 组件相关操作接口
 *
 * @author wangjinnan
 */
@Slf4j
@RestController
@Api(tags = "组件运行中心相关接口", value = "组件运行中心相关接口")
public class ExecutorController {

    @Resource
    TaskService taskService;

    @Resource
    private ConfigService configService;
    @Resource
    private JobService jobService;

    @ApiOperation(value = "启动作业实例", notes = "启动作业实例")
    @PostMapping("/instance/start")
    public ApiResult startInstance(@RequestBody ExecutorParam.InstanceParam instanceParam) throws WamingException {
        InstanceStartRequest request = new InstanceStartRequest();
        request.setInstanceId(instanceParam.getInstanceId());
        request.setJobId(instanceParam.getJobId());
        request.setEnv(instanceParam.getEnv());
        request.setConfigPath(instanceParam.getConfigUrl());
        List<ExecutorStatus> result = null;
        //检查Server 是否存在该文件 不存在即可先在下载到Server节点
        CompInstContext context = ConfigManager.loadByInstanceId(instanceParam.getInstanceId(),instanceParam.getEnv());
        if(context==null) {
            configService.receiverConfig(instanceParam);
        }
        if(ClusterManager.hasAssigned(instanceParam.getJobId())){ //实例已经分配节点
            String nodeId  = ClusterManager.getNodeByInstanceId(instanceParam.getJobId(),instanceParam.getInstanceId());
            if(nodeId==null){
                nodeId  = ClusterManager.getNodeByJobId(instanceParam.getJobId());
                jobService.assignInstance(instanceParam,nodeId);
            } else {
                jobService.startInstance(nodeId,request);
            }
            ExecutorStatus status = new ExecutorStatus();
            status.setInstanceId(instanceParam.getInstanceId());
            status.setExecutorResult(OpResultEnum.SUCCESS.code);
            return ApiResult.success(status);
        }else{  //把该实例分配到随机的一台执行器 assign时需要做大量的文件下载工作，这里不做同步，只发送命令。
            jobService.assignInstance(instanceParam);
            ExecutorStatus status = new ExecutorStatus();
            status.setInstanceId(instanceParam.getInstanceId());
            status.setExecutorResult(OpResultEnum.SUCCESS.code);
            return ApiResult.success(status);
        }
    }
    @ApiOperation(value = "停止作业实例", notes = "停止作业实例")
    @PostMapping("/instance/stop")
    public ApiResult stopInstance(@RequestBody ExecutorParam.InstanceParam instanceParam) throws WamingException {
        String nodeId  = ClusterManager.getNodeByInstanceId(instanceParam.getJobId(),instanceParam.getInstanceId());
        if(nodeId==null){
            ExecutorStatus status = new ExecutorStatus();
            status.setInstanceId(instanceParam.getInstanceId());
            status.setExecutorResult(OpResultEnum.SUCCESS.code);
            status.setMessage("未找到对应的Node节点。直接更改停止状态");
            return ApiResult.success(status);
        }
        InstanceStopRequest request = new InstanceStopRequest();
        request.setInstanceId(instanceParam.getInstanceId());
        request.setEnv(instanceParam.getEnv());
        List<ExecutorStatus> result =  jobService.stopInstance(nodeId,request);
        if(result!=null && result.size()>0){
            return ApiResult.success(result.get(0));
         }else {
            return ApiResult.fail("停止作业实例失败");
        }
    }

    @ApiOperation(value = "清理作业实例", notes = "清理作业实例")
    @PostMapping("/instance/cleanup")
    public ApiResult destroyInstance(@RequestBody ExecutorParam.InstanceParam instanceParam) throws WamingException{
        String nodeId  = ClusterManager.getNodeByInstanceId(instanceParam.getJobId(),instanceParam.getInstanceId());
        if(nodeId==null){
            ExecutorStatus status = new ExecutorStatus();
            status.setInstanceId(instanceParam.getInstanceId());
            status.setExecutorResult(OpResultEnum.SUCCESS.code);
            status.setMessage("未找到对应的Node节点。直接更改删除状态");
            return ApiResult.success(status);
        }

        InstanceRemoveRequest request = new InstanceRemoveRequest();
        request.setInstanceId(instanceParam.getInstanceId());
        request.setEnv(instanceParam.getEnv());
        List<ExecutorStatus> result =   jobService.removeInstance(nodeId,request);
        if(result!=null && result.size()>0){
            return ApiResult.success(result.get(0));
        }else {
            return  ApiResult.fail("清理作业实例失败");
        }
    }

    @ApiOperation(value = "重新配置作业实例", notes = "重新配置作业实例")
    @PostMapping("/instance/reconfig")
    public ApiResult reconfigInstance(@RequestBody ExecutorParam.InstanceParam instanceParam) throws WamingException {
        InstanceStartRequest request = new InstanceStartRequest();
        request.setInstanceId(instanceParam.getInstanceId());
        request.setEnv(instanceParam.getEnv());
        jobService.assignInstance(instanceParam);
        ExecutorStatus status = new ExecutorStatus();
        status.setExecutorResult(OpResultEnum.SUCCESS.code);
        status.setInstanceId(instanceParam.getInstanceId());
        return ApiResult.success(status);
    }

    @ApiOperation(value = "启动作业", notes = "启动作业")
    @PostMapping("/job/start")
    public ApiResult startJob(@RequestBody ExecutorParam.JobParam jobParam) throws WamingException{
        String nodeId  = ClusterManager.getNodeByJobId(jobParam.getJobId());
        JobStartRequest request = new JobStartRequest();
        request.setJobId(jobParam.getJobId());
        request.setEnv(jobParam.getEnv());
        List<ExecutorStatus> result = jobService.startJob(nodeId,request);
        return ApiResult.success(result);
    }

    @ApiOperation(value = "停止作业", notes = "停止作业")
    @PostMapping("/job/stop")
    public ApiResult stopJob(@RequestBody ExecutorParam.JobParam jobParam) throws WamingException {
        String nodeId  = ClusterManager.getNodeByJobId(jobParam.getJobId());
        if(nodeId==null){
            ExecutorStatus status = new ExecutorStatus();
            status.setExecutorResult(OpResultEnum.SUCCESS.code);
            status.setMessage("未找到对应的Node节点。直接更改停止状态");
            return ApiResult.success(status);
        }

        JobStopRequest request = new JobStopRequest();
        request.setJobId(jobParam.getJobId());
        request.setEnv(jobParam.getEnv());
        List<ExecutorStatus> result =jobService.stopJob(nodeId,request);
        return ApiResult.success(result);
    }

    @ApiOperation(value = "清理作业", notes = "清理作业")
    @PostMapping("/job/cleanup")
    public ApiResult destroyJob(@RequestBody ExecutorParam.JobParam jobParam) throws WamingException {
        String nodeId  = ClusterManager.getNodeByJobId(jobParam.getJobId());
        if(nodeId==null){
            ExecutorStatus status = new ExecutorStatus();
            status.setExecutorResult(OpResultEnum.SUCCESS.code);
            status.setMessage("未找到对应的Node节点。直接更改删除状态");
            return ApiResult.success(status);
        }
        JobRemoveRequest request = new JobRemoveRequest();
        request.setJobId(jobParam.getJobId());
        request.setEnv(jobParam.getEnv());
        List<ExecutorStatus> result =jobService.removeJob(nodeId,request);
        return ApiResult.success(result);
    }

    @ApiOperation(value = "重新配置作业并分配启动作业", notes = "重新配置作业并分配启动作业")
    @PostMapping("/job/reconfig")
    public ApiResult reconfigJob(@RequestBody ExecutorParam.JobParam jobParam) throws WamingException {
        jobService.assignJob(jobParam);
        ExecutorStatus status = new ExecutorStatus();
        status.setExecutorResult(OpResultEnum.SUCCESS.code);
        return ApiResult.success(status);
    }

    @ApiOperation(value = "导入作业", notes = "导入作业")
    @PostMapping("/job/import")
    public ApiResult importJob(MultipartFile file) throws WamingException {
        configService.importJob(file, RuntimeConfigKeyConstant.PRO_ENV);
        return ApiResult.success();
    }


    @ApiOperation(value = "提取组件基本配置信息", notes = "提取组件基本配置信息")
    @PostMapping("/component/baseConfig")
    public ApiResult baseConfig(@RequestBody ExecutorParam.ComponentConfigParam compParam) throws WamingException {
        if (compParam.getComponentId() == null || compParam.getComponentNameEn() == null || compParam.getObjectPath() == null){
            return ApiResult.fail("存在非法参数，请检查确认");
        }
        ComponentConfig result = configService.extractBaseConfig(compParam.getComponentId(),
                compParam.getComponentNameEn(),
                compParam.getComponentType(),
                compParam.getRunMode(),
                compParam.getObjectPath());
        return ApiResult.success(result);
    }

    @ApiOperation(value = "提取组件动态输出配置信息", notes = "提取组件动态输出配置信息")
    @PostMapping("/component/syncConfig")
    public ApiResult syncConfig(@RequestBody ExecutorParam.ComponentConfigParam compParam) throws WamingException {
        if (compParam.getComponentId() == null || compParam.getComponentNameEn() == null || compParam.getObjectPath() == null){
            return ApiResult.fail("存在非法参数，请检查确认");
        }
        ComponentConfig result = configService.extractDynamicOutputConfig(compParam.getComponentId(),
                compParam.getComponentNameEn(),
                compParam.getComponentType(),
                compParam.getRunMode(),
                compParam.getParamMap(),
                compParam.getObjectPath());
        return ApiResult.success(result);
    }

    @ApiOperation(value = "执行器websocket地址", notes = "执行器websocket地址")
    @PostMapping("/job/restAddress")
    public ApiResult restAddress(@RequestBody ExecutorParam.InstanceParam instanceParam) throws WamingException {
        CompInstContext context = ClusterManager.getContextByInstanceId(instanceParam.getJobId(),instanceParam.getInstanceId());
        if(context!=null) {
            SystemRuntimeInfo runtimeInfo = context.getSystemRuntimeInfo();
            if (runtimeInfo != null) {
                String restfulAddress = runtimeInfo.getExecutorRestAddress();
                return ApiResult.success(restfulAddress);
            }
        }
        return  ApiResult.fail("无地址信息");
    }
    /////////////////////////////////////////////////////////////////
    /////////////////////定时任务类Job  待删除 TODO/////////////////////
    @ApiOperation(value = "保存或更新到Job", notes = "保存到Job")
    @PostMapping("/instance/saveTask")
    public ApiResult saveTask(@RequestBody ExecutorParam.InstanceParam instance) throws WamingException {
        Long result  = 0L;
        if(instance.getTaskId()==null || instance.getTaskId() <=0) {
            result = taskService.saveJob(instance.getJobId(), instance.getInstanceId(), instance.getCron(), instance.getEnv());
        }else {
            result = taskService.updateJob(instance.getTaskId(), instance.getCron());
        }
        return ApiResult.success(result);
    }

    @ApiOperation(value = "删除Job", notes = "删除Job")
    @PostMapping("/instance/deleteTask")
    public ApiResult deleteTask(@RequestBody ExecutorParam.InstanceParam instance) throws WamingException {
        taskService.deleteJob(instance.getTaskId());
        return ApiResult.success("任务删除成功");
    }


    @ApiOperation(value = "触发Job Task", notes = "触发Job Task")
    @PostMapping("/instance/triggerTask")
    public ApiResult triggerTask(@RequestBody ExecutorParam.InstanceParam instance) throws WamingException {
        taskService.runJob(instance.getTaskId());
        return ApiResult.success("触发作业成功！");
    }

    @ApiOperation(value = "触发Job Task", notes = "触发Job Task")
    @PostMapping("/instance/getTaskCron")
    public ApiResult getCron(@RequestBody ExecutorParam.InstanceParam instance) throws WamingException {
        return ApiResult.fail("未查询到相应的任务表达式");
    }
    ////////////////////////////end////////////
}
